#include "app_buffer.h"

/**
 * @function:  App_SubBuffer_Init
 */
static SubBuffer *app_subBuffer_init(int size)
{
    SubBuffer *sub_buf = (SubBuffer *)malloc(sizeof(SubBuffer)); /* 子缓存结构体空间*/
    sub_buf->buf_ptr = (char *)malloc(size);                     /* 数据缓存空间*/
    sub_buf->buf_size = size;                                    /* 缓存空间长度*/
    sub_buf->data_len = 0;                                       /* 实际数据长度*/

    /*
    note: 注意要返回，所以只能动态分配堆区内存
          栈区内存会释放，返回的是空指针
    */

    return sub_buf;
}

/**
 * @function:  App_Buffer_Init
 */

Buffer *app_buffer_init(int size)
{
    Buffer *buffer = (Buffer *)malloc(sizeof(Buffer));

    buffer->sub_buf[1] = app_subBuffer_init(size);
    buffer->sub_buf[0] = app_subBuffer_init(size);

    buffer->r_index = 0;
    buffer->w_index = 1;

    /* 最后还要加线程互斥锁,避免线程竞争出现问题 */
    pthread_mutex_init(&buffer->r_mutex, NULL);
    pthread_mutex_init(&buffer->w_mutex, NULL);

    // free(buffer->sub_buf[0]->buf_ptr);
    // free(buffer->sub_buf[1]->buf_ptr);
    return buffer;
}

/**
 * @function:  App_Buffer_Write
 */
returnType_t app_buffer_write(Buffer *buffer, char *data, int data_len)
{
    /* 0. 如果数据长度超过255，直接返回，因为长度标识就1个字节 */
    if (data_len > 255)
    {

        log_error("data_len =%d > 255");
        return ERROR;
    }

    /* 1.获取写缓冲区 */
    /* 1.1写之前要加互斥锁 */
    log_debug("写之前上互斥锁");
    pthread_mutex_lock(&buffer->w_mutex);

    /* 1.2再获取写缓冲区 */
    SubBuffer *write_buf = buffer->sub_buf[buffer->w_index];

    /* 1.3判断写缓冲区空间是否足够写入当前数据
     这里实现逻辑为：如果不足就不写，释放互斥锁，返回错误
    */
    if ((write_buf->buf_size - write_buf->data_len) < data_len + 1)
    {
        log_error("写缓冲区空间不足");
        pthread_mutex_unlock(&buffer->w_mutex);
        return ERROR;
    }

    /* 2.写入数据
      数据格式：长度（1Byte）+ 数据
    */
    write_buf->buf_ptr[write_buf->data_len] = data_len;                   /* 写入数据长度 */
    memcpy(&write_buf->buf_ptr[write_buf->data_len + 1], data, data_len); /* 写入数据 */

    /* 3.更新数据长度 */
    write_buf->data_len += data_len + 1; /* 数据长度等于 = 当前数据长度+写入数据长度+写入数据长度标识符（1）*/

    /* 4.写完要释放互斥锁 */
    log_debug("写之后释放互斥锁");
    pthread_mutex_unlock(&buffer->w_mutex);

    return SUCCESS;
}

static void app_swap_buffer(Buffer *buffer)
{
    /* note: 别人写的时候你可不能去交换 */
    pthread_mutex_lock(&buffer->w_mutex);
    log_debug("交换前: r_index=%d,w_index=%d", buffer->r_index, buffer->w_index);
    int tmp_index = 0;
    tmp_index = buffer->r_index;
    buffer->r_index = buffer->w_index;
    buffer->w_index = tmp_index;
    log_debug("交换后: r_index=%d,w_index=%d", buffer->r_index, buffer->w_index);
    pthread_mutex_unlock(&buffer->w_mutex);
}

/**
 * @function:  读取缓冲区内容
 * @param:     buffer: 要读取的缓冲区结构体
 * @param:     buf:    将读到的数据缓存在这
 * @param:     buf_len: 缓存区大小
 * @return:    -1: 读取失败  >=0: 读取到的实际数据长度
 * @note:  注意这个函数是读取首个有效数据帧，然后删除该数据帧（也就是将后面数据帧的挪到前面来）
 */
int app_buffer_read(Buffer *buffer, char *buf, int buf_len)
{
    /* 1.获取读缓冲区 */
    log_debug("读之前上互斥锁");
    pthread_mutex_lock(&buffer->r_mutex);

    SubBuffer *read_buf = buffer->sub_buf[buffer->r_index]; /* 获取读缓存的内存地址 */

    /* 2. 读取数据 */

    /* 2.1 如果没有数据就交换读写缓存 */
    if (read_buf->data_len == 0)
    {
        log_debug("没有数据，交换读写缓存");
        app_swap_buffer(buffer);

        /* 注意要再次获取读缓存 */
        read_buf = buffer->sub_buf[buffer->r_index];

        if (read_buf->data_len == 0)
        {
            log_error("没有数据，交换读写缓存后，仍然没有数据");
            pthread_mutex_unlock(&buffer->r_mutex);
            return -1;
        }
    }

    /* 2.2 读取数据 */

    /* note ：read_buf->buf_ptr[0] 为char ：-128-127 */
    int data_len = (__uint8_t)read_buf->buf_ptr[0]; /* 获取第1个数据帧的长度 */
    log_debug("读取到的数据长度为%d", data_len);

    if (buf_len < data_len) /* 接收空间大小检测 */
    {
        log_error("buf_len < data_len");
        pthread_mutex_unlock(&buffer->r_mutex);
        return -1;
    }

    memcpy(buf, read_buf->buf_ptr + 1, data_len); /* 将第1个数据拷贝到buf中 */

    /* 3. 删除读取到的数据（就是数组的移位覆盖）
     参数1：移到哪？：移到数组头 read_buf->buf_ptr == &read_buf->buf_ptr[0]
     参数2：从哪里开始移？看你读了多少：read_buf->buf_ptr + 1 + data_len
     参数3：移多长？看你剩余元素  ：当前长度 - 1（长度标识字节）- 已读长度
    */
    memmove(read_buf->buf_ptr, read_buf->buf_ptr + 1 + data_len, read_buf->data_len - (1 + data_len));

    /* 4. 更新数据长度 */
    // read_buf->buf_ptr -= (1 + data_len);
    read_buf->data_len -= (1 + data_len);
    


    


    /* 5. 释放互斥锁 */
    log_debug("读之后释放互斥锁");
    pthread_mutex_unlock(&buffer->r_mutex);

    /*6.返回读到的数据长度*/
    return data_len;
}

/**
 * @function:  App_Buffer_Free
 *             释放所有 malloc 动态分配的内存空间
 *
 */
returnType_t app_buffer_free(Buffer *buffer)
{
    /* 释放子空间缓存 */
    free(buffer->sub_buf[0]->buf_ptr);
    free(buffer->sub_buf[1]->buf_ptr);

    /* 释放子空间结构体 */
    free(buffer->sub_buf[0]);
    free(buffer->sub_buf[1]);

    /* 释放父结构体 */
    free(buffer);
}